package com.rickpan.service;

import com.rickpan.dto.request.LoginRequest;
import com.rickpan.dto.request.RegisterRequest;
import com.rickpan.dto.response.LoginResponse;
import com.rickpan.dto.response.UserResponse;
import com.rickpan.entity.User;
import com.rickpan.exception.BusinessException;
import com.rickpan.repository.UserRepository;
import com.rickpan.security.JwtTokenProvider;
import com.rickpan.service.UserOnlineService;
import com.rickpan.service.CaptchaService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.Map;

/**
 * 认证服务
 */
@Service
@Transactional
public class AuthService {

    private static final Logger logger = LoggerFactory.getLogger(AuthService.class);

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private JwtTokenProvider tokenProvider;

    @Autowired
    private UserOnlineService userOnlineService;

    @Autowired
    private CaptchaService captchaService;

    /**
     * 用户注册
     */
    public UserResponse register(RegisterRequest request) {
        logger.info("用户注册请求: {}", request);

        // 检查用户名是否已存在
        if (userRepository.existsByUsername(request.getUsername())) {
            throw new BusinessException("用户名已存在");
        }

        // 检查邮箱是否已存在
        if (userRepository.existsByEmail(request.getEmail())) {
            throw new BusinessException("邮箱已存在");
        }

        // 创建新用户
        User user = new User();
        user.setUsername(request.getUsername());
        user.setEmail(request.getEmail());
        user.setPassword(passwordEncoder.encode(request.getPassword()));
        user.setRealName(request.getRealName());
        user.setRole(User.Role.USER);
        user.setStatus(User.Status.ACTIVE);

        User savedUser = userRepository.save(user);
        logger.info("用户注册成功: {}", savedUser.getUsername());

        return UserResponse.from(savedUser);
    }

    /**
     * 用户登录
     */
    public LoginResponse login(LoginRequest request) {
        logger.info("用户登录请求: {}", request);

        // 验证验证码
        if (request.getCaptcha() == null || request.getCaptchaId() == null) {
            throw new BusinessException("验证码不能为空");
        }

        if (!captchaService.validateCaptcha(request.getCaptchaId(), request.getCaptcha())) {
            throw new BusinessException("验证码错误或已过期");
        }

        // 认证用户
        Authentication authentication = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(
                        request.getUsername(),
                        request.getPassword()
                )
        );

        SecurityContextHolder.getContext().setAuthentication(authentication);

        // 获取用户信息
        User user = userRepository.findByUsernameOrEmail(request.getUsername())
                .orElseThrow(() -> new BusinessException("用户不存在"));

        // 检查用户状态
        if (user.getStatus() == User.Status.DISABLED) {
            throw new BusinessException("账户已被禁用");
        }

        // 生成JWT Token
        String token = tokenProvider.generateToken(user.getId(), user.getUsername());

        // 设置用户在线状态
        try {
            String sessionId = "session_" + System.currentTimeMillis() + "_" + user.getId();
            Map<String, Object> clientInfo = new HashMap<>();
            clientInfo.put("loginType", "WEB_LOGIN");
            clientInfo.put("loginTime", java.time.LocalDateTime.now().toString());

            userOnlineService.userOnline(user.getId(), sessionId, clientInfo);
            logger.info("用户在线状态设置成功: userId={}", user.getId());
        } catch (Exception e) {
            logger.error("设置用户在线状态失败: userId={}", user.getId(), e);
        }

        logger.info("用户登录成功: username={}, userId={}, role={}, userType={}",
                   user.getUsername(), user.getId(), user.getRole(), user.getUserType());

        return new LoginResponse(token, UserResponse.from(user));
    }

    /**
     * 获取当前用户信息
     */
    public UserResponse getCurrentUser(Long userId) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new BusinessException("用户不存在"));

        return UserResponse.from(user);
    }

    /**
     * 刷新Token
     */
    public String refreshToken(String token) {
        if (!tokenProvider.validateToken(token)) {
            throw new BusinessException("无效的Token");
        }

        String newToken = tokenProvider.refreshToken(token);
        if (newToken == null) {
            throw new BusinessException("Token刷新失败");
        }

        return newToken;
    }

    /**
     * 用户登出
     */
    public void logout(Long userId) {
        try {
            // 清除用户在线状态
            if (userId != null) {
                userOnlineService.forceUserOffline(userId);
                logger.info("用户在线状态清除成功: userId={}", userId);
            }
        } catch (Exception e) {
            logger.error("清除用户在线状态失败: userId={}", userId, e);
        }

        SecurityContextHolder.clearContext();
        logger.info("用户登出成功: userId={}", userId);
    }

    /**
     * 设置用户在线状态
     */
    public void setUserOnline(Long userId, String sessionId, Map<String, Object> clientInfo) {
        try {
            userOnlineService.userOnline(userId, sessionId, clientInfo);
            logger.info("用户在线状态设置成功: userId={}, sessionId={}", userId, sessionId);
        } catch (Exception e) {
            logger.error("设置用户在线状态失败: userId={}, sessionId={}", userId, sessionId, e);
            throw new BusinessException("设置在线状态失败");
        }
    }

    /**
     * 检查用户名是否可用
     */
    public boolean isUsernameAvailable(String username) {
        return !userRepository.existsByUsername(username);
    }

    /**
     * 检查邮箱是否可用
     */
    public boolean isEmailAvailable(String email) {
        return !userRepository.existsByEmail(email);
    }
}
